/**
 * Created by W.Qiong on 14-6-10.
 */
/**
 * Created by W.Qiong on 14-6-10.
 */
(function ($, window, document, undefined) {

    $.fn.popupExt = function(parameters) {
        var
            $allModules     = $(this),
            $document       = $(document),

            moduleSelector  = $allModules.selector || '',

            time            = new Date().getTime(),
            performance     = [],

            query           = arguments[0],
            methodInvoked   = (typeof query == 'string'),
            queryArguments  = [].slice.call(arguments, 1),

            returnedValue
            ;
        $allModules
            .each(function() {
                var
                    settings        = ( $.isPlainObject(parameters) )
                        ? $.extend(true, {}, $.fn.popup.settings, parameters)
                        : $.extend({}, $.fn.popup.settings),

                    selector        = settings.selector,
                    className       = settings.className,
                    error           = settings.error,
                    metadata        = settings.metadata,
                    namespace       = settings.namespace,

                    eventNamespace  = '.' + settings.namespace,
                    moduleNamespace = 'module-' + namespace,

                    $module         = $(this),
                    $context        = $(settings.context),
                    $target         = (settings.target)
                        ? $(settings.target)
                        : $module,

                    $window         = $(window),

                    $offsetParent   = (settings.inline)
                        ? $target.offsetParent()
                        : $window,
                    $popup          = (settings.inline)
                        ? $target.next(settings.selector.popup)
                        : $window.children(settings.selector.popup).last(),

                    searchDepth     = 0,

                    element         = this,
                    instance        = $module.data(moduleNamespace),
                    module
                    ;

                module = {

                    // binds events
                    initialize: function() {
                        module.debug('Initializing module', $module);
                        if(settings.on == 'click') {
                            $module
                                .on('click', module.toggle)
                            ;
                        }
                        else {
                            $module
                                .on(module.get.startEvent() + eventNamespace, module.event.start)
//                                .on(module.get.endEvent() + eventNamespace, module.event.end)
                            ;
                        }
                        if(settings.target) {
                            module.debug('Target set to element', $target);
                        }
                        $window
                            .on('resize' + eventNamespace, module.event.resize)
                        ;
                        module.instantiate();
                    },

                    instantiate: function() {
                        module.verbose('Storing instance of module', module);
                        instance = module;
                        $module
                            .data(moduleNamespace, instance)
                        ;
                    },

                    refresh: function() {
                        if(settings.inline) {
                            $popup = $target.next(selector.popup);
                            $offsetParent = $target.offsetParent();
                        }
                        else {
                            $popup = $window.children(selector.popup).last();
                        }
                    },

                    destroy: function() {
                        module.debug('Destroying previous module');
                        $window
                            .off(eventNamespace)
                        ;
                        $popup
                            .remove()
                        ;
                        $module
                            .off(eventNamespace)
                            .removeData(moduleNamespace)
                        ;
                    },

                    event: {
                        start:  function(event) {
                            module.timer = setTimeout(function() {
                                if( module.is.hidden() ) {
                                    module.show();
                                }
                            }, settings.delay);
                        },
                        end:  function() {
                            clearTimeout(module.timer);
                            if( module.is.visible() ) {
                                module.hide();
                            }
                        },
                        resize: function() {
                            if( module.is.visible() ) {
                                module.set.position();
                            }
                        }
                    },

                    // generates popup html from metadata
                    create: function() {
                        module.debug('Creating pop-up html');
                        var
                            html      = $module.data(metadata.html)      || settings.html,
                            variation = $module.data(metadata.variation) || settings.variation,
                            title     = $module.data(metadata.title)     || settings.title,
                            content   = $module.data(metadata.content)   || $module.attr('title') || settings.content
                            ;

                       // 修改 html指定为选择器
                        if(html || content || title) {
                            if(!html||!$(html)) {
                                html = settings.template({
                                    title   : title,
                                    content : content
                                });
                                $popup = $('<div/>')
                                    .addClass(className.popup)
                                    .addClass(variation)
                                    .addClass(className.canremove)//作为可删除的标识
                                    .html(html)
                                ;
                            }else{
                                $popup = $('<div/>')
                                    .addClass(className.popup)
                                    .addClass(variation)
                                    .html(settings.template({
                                        title : title,
                                        content: null
                                    }))
                                ;
                                $(html).removeClass("hide");
                                $(html).show();
                                $(html).appendTo($popup);
                            }

                            if(settings.inline) {
                                module.verbose('Inserting popup element inline', $popup);
                                $popup
                                    .data(moduleNamespace, instance)
                                    .insertAfter($module)
                                ;
                            }
                            else {
                                module.verbose('Appending popup element to body', $popup);
                                $popup
                                    .data(moduleNamespace, instance)
                                    .appendTo( $context )
                                ;
                            }
                            $.proxy(settings.onCreate, $popup)();

                            //关闭按钮
                            $popup.find(settings.selector.close).on("click",module.event.end);

                            //防止多次绑定
                            if(settings.closebtn !=""){
                                var d =$(settings.closebtn).data();
                                if($.isEmptyObject(d)){
                                    $(settings.closebtn).data({isBind:true});
                                    $(settings.closebtn).bind("click",module.event.end);
                                }
                            }
                        }
                        else {
                            module.error(error.content);
                        }
                    },

                    // determines popup state
                    toggle: function() {
                        module.debug('Toggling pop-up');
                        if( module.is.hidden() ) {
                            module.debug('Popup is hidden, showing pop-up');
                            module.unbind.close();
                            module.hideAll();
                            module.show();
                        }
                        else {
                            module.debug('Popup is visible, hiding pop-up');
                            module.hide();
                        }
                    },

                    show: function(callback) {
                        callback = callback || function(){};
                        module.debug('Showing pop-up', settings.transition);
                        if(!settings.preserve) {
                            module.refresh();
                        }
                        if( !module.exists() ) {
                            module.create();
                        }
                        module.save.conditions();
                        module.set.position();
                        module.animate.show(callback);
                    },


                    hide: function(callback) {
                        callback = callback || function(){};
                        $module
                            .removeClass(className.visible)
                        ;
                        module.restore.conditions();
                        module.unbind.close();
                        if( module.is.visible() ) {
                            module.animate.hide(callback);
                        }
                    },

                    hideAll: function() {
                        $(selector.popup)
                            .filter(':visible')
                            .popup('hide')
                        ;
                    },

                    hideGracefully: function(event) {
                        // don't close on clicks inside popup
                        if(event && $(event.target).closest(selector.popup).size() === 0) {
                            module.debug('Click occurred outside popup hiding popup');
                            module.hide();
                        }
                        else {
                            module.debug('Click was inside popup, keeping popup open');
                        }
                    },

                    exists: function() {
                        if(settings.inline) {
                            return ( $popup.size() !== 0 );
                        }
                        else {
                            return ( $popup.parent($context).size() );
                        }
                    },

                    remove: function() {
                        module.debug('Removing popup');
                        if(!$popup.hasClass(className.canremove)){
                            $popup.children(settings.html)
                                .appendTo($($context));
//                            $(settings.html).addClass("hide");
                            $(settings.html).hide();
                        }
                        //不删除  只做隐藏
                        $popup.remove();
                    },

                    save: {
                        conditions: function() {
                            module.cache = {
                                title: $module.attr('title')
                            };
                            if (module.cache.title) {
                                $module.removeAttr('title');
                            }
                            module.verbose('Saving original attributes', module.cache.title);
                        }
                    },
                    restore: {
                        conditions: function() {
                            if(module.cache && module.cache.title) {
                                $module.attr('title', module.cache.title);
                                module.verbose('Restoring original attributes', module.cache.title);
                            }
                            return true;
                        }
                    },
                    animate: {
                        show: function(callback) {
                            callback = callback || function(){};
                            $module
                                .addClass(className.visible)
                            ;
                            if(settings.transition && $.fn.transition !== undefined && $module.transition('is supported')) {
                                $popup
                                    .transition(settings.transition + ' in', settings.duration, function() {
                                        module.bind.close();
                                        $.proxy(callback, element)();
                                    })
                                ;
                            }
                            else {
                                $popup
                                    .stop()
                                    .fadeIn(settings.duration, settings.easing, function() {
                                        module.bind.close();
                                        $.proxy(callback, element)();
                                    })
                                ;
                            }
                            $.proxy(settings.onShow, element)();
                        },
                        hide: function(callback) {
                            callback = callback || function(){};
                            module.debug('Hiding pop-up');
                            if(settings.transition && $.fn.transition !== undefined && $module.transition('is supported')) {
                                $popup
                                    .transition(settings.transition + ' out', settings.duration, function() {
                                        module.reset();
                                        callback();
                                    })
                                ;
                            }
                            else {
                                $popup
                                    .stop()
                                    .fadeOut(settings.duration, settings.easing, function() {
                                        module.reset();
                                        callback();
                                    })
                                ;
                            }
                            $.proxy(settings.onHide, element)();
                        }
                    },

                    get: {
                        startEvent: function() {
                            if(settings.on == 'hover') {
                                return 'mouseenter';
                            }
                            else if(settings.on == 'focus') {
                                return 'focus';
                            }
                        },
                        endEvent: function() {
                            if(settings.on == 'hover') {
                                return 'mouseleave';
                            }
                            else if(settings.on == 'focus') {
                                return 'blur';
                            }
                        },
                        offstagePosition: function() {
                            var
                                boundary  = {
                                    top    : $(window).scrollTop(),
                                    bottom : $(window).scrollTop() + $(window).height(),
                                    left   : 0,
                                    right  : $(window).width()
                                },
                                popup     = {
                                    width    : $popup.width(),
                                    height   : $popup.outerHeight(),
                                    position : $popup.offset()
                                },
                                offstage  = {},
                                offstagePositions = []
                                ;
                            if(popup.position) {
                                offstage = {
                                    top    : (popup.position.top < boundary.top),
                                    bottom : (popup.position.top + popup.height > boundary.bottom),
                                    right  : (popup.position.left + popup.width > boundary.right),
                                    left   : (popup.position.left < boundary.left)
                                };
                            }
                            module.verbose('Checking if outside viewable area', popup.position);
                            // return only boundaries that have been surpassed
                            $.each(offstage, function(direction, isOffstage) {
                                if(isOffstage) {
                                    offstagePositions.push(direction);
                                }
                            });
                            return (offstagePositions.length > 0)
                                ? offstagePositions.join(' ')
                                : false
                                ;
                        },
                        nextPosition: function(position) {
                            switch(position) {
                                case 'top left':
                                    position = 'bottom left';
                                    break;
                                case 'bottom left':
                                    position = 'top right';
                                    break;
                                case 'top right':
                                    position = 'bottom right';
                                    break;
                                case 'bottom right':
                                    position = 'top center';
                                    break;
                                case 'top center':
                                    position = 'bottom center';
                                    break;
                                case 'bottom center':
                                    position = 'right center';
                                    break;
                                case 'right center':
                                    position = 'left center';
                                    break;
                                case 'left center':
                                    position = 'top center';
                                    break;
                            }
                            return position;
                        }
                    },

                    set: {
                        position: function(position, arrowOffset) {
                            var
                                windowWidth  = $(window).width(),
                                windowHeight = $(window).height(),

                                width        = $target.outerWidth(),
                                height       = $target.outerHeight(),

                                popupWidth   = $popup.width(),
                                popupHeight  = $popup.outerHeight(),

                                parentWidth  = $offsetParent.outerWidth(),
                                parentHeight = $offsetParent.outerHeight(),

                                distanceAway = settings.distanceAway,

                                offset       = (settings.inline)
                                    ? $target.position()
                                    : $target.offset(),

                                positioning,
                                offstagePosition
                                ;
                            position    = position    || $module.data(metadata.position)    || settings.position;
                            arrowOffset = arrowOffset || $module.data(metadata.offset)      || settings.offset;
                            // adjust for margin when inline
                            if(settings.inline) {
                                if(position == 'left center' || position == 'right center') {
                                    arrowOffset  += parseInt( window.getComputedStyle(element).getPropertyValue('margin-top'), 10);
                                    distanceAway += -parseInt( window.getComputedStyle(element).getPropertyValue('margin-left'), 10);
                                }
                                else {
                                    arrowOffset  += parseInt( window.getComputedStyle(element).getPropertyValue('margin-left'), 10);
                                    distanceAway += parseInt( window.getComputedStyle(element).getPropertyValue('margin-top'), 10);
                                }
                            }
                            module.debug('Calculating offset for position', position);
                            switch(position) {
                                case 'top left':
                                    positioning = {
                                        bottom :  parentHeight - offset.top + distanceAway,
                                        right  :  parentWidth - offset.left - arrowOffset,
                                        top    : 'auto',
                                        left   : 'auto'
                                    };
                                    break;
                                case 'top center':
                                    positioning = {
                                        bottom :  parentHeight - offset.top + distanceAway,
                                        left   : offset.left + (width / 2) - (popupWidth / 2) + arrowOffset,
                                        top    : 'auto',
                                        right  : 'auto'
                                    };
                                    break;
                                case 'top right':
                                    positioning = {
                                        top    : 'auto',
                                        bottom :  parentHeight - offset.top + distanceAway,
                                        left   : offset.left + width + arrowOffset,
                                        right  : 'auto'
                                    };
                                    break;
                                case 'left center':
                                    positioning = {
                                        top    :  offset.top + (height / 2) - (popupHeight / 2) + arrowOffset,
                                        right  : parentWidth - offset.left + distanceAway,
                                        left   : 'auto',
                                        bottom : 'auto'
                                    };
                                    break;
                                case 'right center':
                                    positioning = {
                                        top    :  offset.top + (height / 2) - (popupHeight / 2) + arrowOffset,
                                        left   : offset.left + width + distanceAway,
                                        bottom : 'auto',
                                        right  : 'auto'
                                    };
                                    break;
                                case 'bottom left':
                                    positioning = {
                                        top    :  offset.top + height + distanceAway,
                                        right  : parentWidth - offset.left - arrowOffset,
                                        left   : 'auto',
                                        bottom : 'auto'
                                    };
                                    break;
                                case 'bottom center':
                                    positioning = {
                                        top    :  offset.top + height + distanceAway,
                                        left   : offset.left + (width / 2) - (popupWidth / 2) + arrowOffset,
                                        bottom : 'auto',
                                        right  : 'auto'
                                    };
                                    break;
                                case 'bottom right':
                                    positioning = {
                                        top    :  offset.top + height + distanceAway,
                                        left   : offset.left + width + arrowOffset,
                                        bottom : 'auto',
                                        right  : 'auto'
                                    };
                                    break;
                            }
                            // tentatively place on stage
                            $popup
                                .css(positioning)
                                .removeClass(className.position)
                                .addClass(position)
                                .addClass(className.loading)
                            ;
                            // check if is offstage
                            offstagePosition = module.get.offstagePosition();

                            // recursively find new positioning
                            if(offstagePosition) {
                                module.debug('Element is outside boundaries', offstagePosition);
                                if(searchDepth < settings.maxSearchDepth) {
                                    position = module.get.nextPosition(position);
                                    searchDepth++;
                                    module.debug('Trying new position', position);
                                    return module.set.position(position);
                                }
                                else {
                                    module.error(error.recursion);
                                    searchDepth = 0;
                                    module.reset();
                                    $popup.removeClass(className.loading);
                                    return false;
                                }
                            }
                            else {
                                module.debug('Position is on stage', position);
                                searchDepth = 0;
                                $popup.removeClass(className.loading);
                                return true;
                            }
                        }

                    },

                    bind: {
                        close:function() {
                            if(settings.on == 'click' && settings.closable) {
                                module.verbose('Binding popup close event to document');
                                $document
                                    .on('click' + eventNamespace, function(event) {
                                        module.verbose('Pop-up clickaway intent detected');
                                        $.proxy(module.hideGracefully, this)(event);
                                    })
                                ;
                            }
                        }
                    },

                    unbind: {
                        close: function() {
                            if(settings.on == 'click' && settings.closable) {
                                module.verbose('Removing close event from document');
                                $document
                                    .off('click' + eventNamespace)
                                ;
                            }
                        }
                    },

                    is: {
                        animating: function() {
                            return ( $popup.is(':animated') || $popup.hasClass(className.animating) );
                        },
                        visible: function() {
                            return $popup.is(':visible');
                        },
                        hidden: function() {
                            return !module.is.visible();
                        }
                    },

                    reset: function() {
                        $popup
                            .attr('style', '')
                            .removeAttr('style')
                        ;
                        if(!settings.preserve) {
                            module.remove();
                        }
                    },

                    setting: function(name, value) {
                        if( $.isPlainObject(name) ) {
                            $.extend(true, settings, name);
                        }
                        else if(value !== undefined) {
                            settings[name] = value;
                        }
                        else {
                            return settings[name];
                        }
                    },
                    internal: function(name, value) {
                        if( $.isPlainObject(name) ) {
                            $.extend(true, module, name);
                        }
                        else if(value !== undefined) {
                            module[name] = value;
                        }
                        else {
                            return module[name];
                        }
                    },
                    debug: function() {
                        if(settings.debug) {
                            if(settings.performance) {
                                module.performance.log(arguments);
                            }
                            else {
                                module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
                                module.debug.apply(console, arguments);
                            }
                        }
                    },
                    verbose: function() {
                        if(settings.verbose && settings.debug) {
                            if(settings.performance) {
                                module.performance.log(arguments);
                            }
                            else {
                                module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
                                module.verbose.apply(console, arguments);
                            }
                        }
                    },
                    error: function() {
                        module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
                        module.error.apply(console, arguments);
                    },
                    performance: {
                        log: function(message) {
                            var
                                currentTime,
                                executionTime,
                                previousTime
                                ;
                            if(settings.performance) {
                                currentTime   = new Date().getTime();
                                previousTime  = time || currentTime;
                                executionTime = currentTime - previousTime;
                                time          = currentTime;
                                performance.push({
                                    'Element'        : element,
                                    'Name'           : message[0],
                                    'Arguments'      : [].slice.call(message, 1) || '',
                                    'Execution Time' : executionTime
                                });
                            }
                            clearTimeout(module.performance.timer);
                            module.performance.timer = setTimeout(module.performance.display, 100);
                        },
                        display: function() {
                            var
                                title = settings.name + ':',
                                totalTime = 0
                                ;
                            time = false;
                            clearTimeout(module.performance.timer);
                            $.each(performance, function(index, data) {
                                totalTime += data['Execution Time'];
                            });
                            title += ' ' + totalTime + 'ms';
                            if(moduleSelector) {
                                title += ' \'' + moduleSelector + '\'';
                            }
                            if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
                                console.groupCollapsed(title);
                                if(console.table) {
                                    console.table(performance);
                                }
                                else {
                                    $.each(performance, function(index, data) {
                                        console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
                                    });
                                }
                                console.groupEnd();
                            }
                            performance = [];
                        }
                    },
                    invoke: function(query, passedArguments, context) {
                        var
                            object = instance,
                            maxDepth,
                            found,
                            response
                            ;
                        passedArguments = passedArguments || queryArguments;
                        context         = element         || context;
                        if(typeof query == 'string' && object !== undefined) {
                            query    = query.split(/[\. ]/);
                            maxDepth = query.length - 1;
                            $.each(query, function(depth, value) {
                                var camelCaseValue = (depth != maxDepth)
                                        ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
                                        : query
                                    ;
                                if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
                                    object = object[camelCaseValue];
                                }
                                else if( object[camelCaseValue] !== undefined ) {
                                    found = object[camelCaseValue];
                                    return false;
                                }
                                else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
                                    object = object[value];
                                }
                                else if( object[value] !== undefined ) {
                                    found = object[value];
                                    return false;
                                }
                                else {
                                    return false;
                                }
                            });
                        }
                        if ( $.isFunction( found ) ) {
                            response = found.apply(context, passedArguments);
                        }
                        else if(found !== undefined) {
                            response = found;
                        }
                        if($.isArray(returnedValue)) {
                            returnedValue.push(response);
                        }
                        else if(returnedValue !== undefined) {
                            returnedValue = [returnedValue, response];
                        }
                        else if(response !== undefined) {
                            returnedValue = response;
                        }
                        return found;
                    }
                };

                if(methodInvoked) {
                    if(instance === undefined) {
                        module.initialize();
                    }
                    module.invoke(query);
                }
                else {
                    if(instance !== undefined) {
                        module.destroy();
                    }
                    module.initialize();
                }
            })
        ;

        return (returnedValue !== undefined)
            ? returnedValue
            : this
            ;
    };

    $.fn.popup.settings = {

        name           : 'Popup',
        debug          : false,
        verbose        : true,
        performance    : true,
        namespace      : 'popup',

        onCreate       : function(){},
        onShow         : function(){},
        onHide         : function(){},

        variation      : '',
        content        : false,
        html           : false,
        title          : false,

        on             : 'hover',
        target         : false,
        closable       : true,

        context        : 'body',
        position       : 'top center',
        delay          : 150,
        inline         : false,
        preserve       : false,

        duration       : 250,
        easing         : 'easeOutQuint',
        transition     : 'scale',

        distanceAway   : 0,
        offset         : 0,
        maxSearchDepth : 10,

        error: {
            content   : 'Your popup has no content specified',
            method    : 'The method you called is not defined.',
            recursion : 'Popup attempted to reposition element to fit, but could not find an adequate position.'
        },

        metadata: {
            content   : 'content',
            html      : 'html',
            offset    : 'offset',
            position  : 'position',
            title     : 'title',
            variation : 'variation'
        },

        className   : {
            animating   : 'animating',
            loading     : 'loading',
            popup       : 'ui popup',
            position    : 'top left center bottom right',
            visible     : 'visible',
            canremove   :"canremove"
        },

        selector    : {
            popup    : '.ui.popup',
            close    : '.close' //控制关闭按钮的
        },

        closebtn:"",//扩展关闭弹出框 按钮选择器配置

        template: function(text) {
            var html = '';
            if(typeof text !== undefined) {
                if(typeof text.title !== undefined && text.title) {
                    html += '<div class="header">'
                        +text.title
//                        + '<div class="ui inverted black block header">'
                        +'<i class="icon close right"></i>'
//                        +'</div>'
                        +'</div>';
                }
                if(typeof text.content !== undefined && text.content) {
                    html += '<div class="content">' + text.content + '</div>';
                }
            }
            return html;
        }

    };

})( jQuery, window , document );
